#include "Epoll.h"

Epoll::Epoll()
{
    if((epollfd_ = epoll_create(1)) == -1)   //创建epoll句柄(红黑树)
    {
        printf("epoll_create() failed(%d).\n",errno);
        exit(-1);
    }
}

Epoll::~Epoll()     //关闭epollfd_
{
    close(epollfd_);
}

//把Channel类添加/更新到红黑树，channel类中有fd，也有需要监视的事件
void Epoll::updatechannel(Channel* ch)                        
{
    epoll_event ev;             //声明事件的数据结构
    ev.data.ptr = ch;           //指定Channel
    ev.events = ch->events();   //指定事件

    if(ch->inpoll())    //如果Channel已经在树上
    {
        //更新事件
        if(epoll_ctl(epollfd_, EPOLL_CTL_MOD, ch->fd(), &ev) == -1)
        {
            perror("epoll_mod() failed.\n");
            exit(-1);
        }
    }
    else                //如果Channel不在树上
    {
        //添加事件
        if(epoll_ctl(epollfd_, EPOLL_CTL_ADD, ch->fd(), &ev) == -1)
        {
            perror("epoll_ctl() failed.\n");
            exit(-1);
        }
        ch->setinepoll();   //把Channel的inepoll_成员设置为true
    }
}

//把channel从红黑树删除
void Epoll::removeChannel(Channel* ch)
{
    if(ch->inpoll())    //如果Channel已经在树上
    {
        printf("remove Channel\n");
        //更新事件
        if(epoll_ctl(epollfd_, EPOLL_CTL_DEL, ch->fd(), 0) == -1)
        {
            perror("epoll_del() failed.\n");
            exit(-1);
        }
    }
}

//运行epoll_wait(),等待的事件的发生，返回已发生的事件
std::vector<Channel*> Epoll::loop(int timeout)   
{
    std::vector<Channel*> channels;   //存放epoll_wait()返回的事件。

    bzero(events_, sizeof(events_));
    int infds = epoll_wait(epollfd_, events_, MaxEvents, timeout);   //等待事件发生,timeout设置为超时等待

    //返回失败
    if(infds < 0)
    {
        //EBADF:epfd不是一个有效的描述符
        //EFAULT:参数events指向的内存区域不可写
        //EINVAL:epfd不是一个epoll文件描述符,或者参数maxevents小于等于0
        //EINTR:阻塞过程中被信号中断,epoll_pwait()可以避免,或者错误处理中,解析error后重新调用epoll_wait()

        perror("epoll_wait() failed");
        exit(-1);
    }

    //超时
    if(infds == 0)
    {
        //epoll_wait()超时,系统空闲，返回空的channels
        return channels;
    }
    
    //有事件发生
    for(int i = 0; i < infds; i++)
    {
        //evs.push_back(events_[i]);
        Channel* ch = (Channel*)events_[i].data.ptr;    //取出已发生事件的channel
        ch->setrevents(events_[i].events);              //设置channel的revents_成员
        channels.push_back(ch);
    }

    return channels;
}

